﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Functions;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Functions.Readers;
using TSU.FAMC.ComputerEngineering.Classes.Circuits;
using TSU.FAMC.ComputerEngineering.Classes.Circuits.Readers;
using TSU.FAMC.ComputerEngineering.Classes.Diagnostics;
using TSU.FAMC.ComputerEngineering.Classes.Diagnostics.PathDelayFaults;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Fundamental;
using TSU.FAMC.ComputerEngineering.Classes.Enums;
using TSU.FAMC.ComputerEngineering.Classes.OrandTrees;
using TSU.FAMC.ComputerEngineering.Classes.OrandTrees.Readers;

namespace FullTestBuilder
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            if (openFileDialog1.FileNames.Length == 0)
            {
                MessageBox.Show("Не выбрано ни одного файла системы для построения тестов!");
                return;
            }

            // reading files
            reportBox.Clear();
            var errorsCounter = 0;
            var pdfTests = new List<PdfAnalyzer>();
            var abTests = new List<AbFaultAnalyzer>();
            var successCircuitsFiles = new List<String>();
            var sucessCircuits = new List<Circuit>();
            var sucessSystems = new List<BooleanSystem>();
            foreach (var fileName in openFileDialog1.FileNames)
            {
                var fileStr = String.Empty;

                try
                {
                    // reading file
                    var streamReader = new StreamReader(fileName);
                    fileStr = streamReader.ReadToEnd();
                }
                catch (Exception ex)
                {
                    reportBox.Text += string.Format("{0}.\r\n Ошибка: не удалось прочитать файл. Подрбнее: {1} \r\n\r\n", fileName, ex.Message);
                    errorsCounter++;
                    continue;
                }

                // reading circuit

                var circuitReader = new CircuitReaderPlain {Input = fileStr};

                try
                {
                    circuitReader.Read();
                }
                catch (Exception ex)
                {
                    reportBox.Text += string.Format("{0}.\r\n Ошибка: не удалось прочитать схему. Подрбнее: {1} \r\n\r\n", fileName, ex.Message);
                    errorsCounter++;
                    continue;
                }


                // building ORANDTree from circuit
                var tree = new OrandTree();

                // reading tree from circuit
                var readerORANDTree = new OrandTreeReaderCircuit();
                readerORANDTree.Input = circuitReader.Circuit;
                readerORANDTree.Read();
                tree = readerORANDTree.Tree;

                // tree system
                var system = new BooleanSystem();

                // reading system from ORANDTree
                var readerSytemFromORANDTree = new BooleanSystemReaderOrandTree();
                readerSytemFromORANDTree.Input = tree;
                readerSytemFromORANDTree.System = system;
                readerSytemFromORANDTree.Read();

                // building tests
                var pdfAnalyzer = new PdfAnalyzer();
                var abfAnalyzer = new AbFaultAnalyzer();
                try
                {
                    // analyzing for PDF
                    
                    pdfAnalyzer.BuildTest(circuitReader.Circuit);

                    // analyzing for ABF
                    abfAnalyzer.BuildTest(system);

                    // saving tests
                    pdfTests.Add(pdfAnalyzer);
                    abTests.Add(abfAnalyzer);
                }
                catch (Exception ex)
                {
                    reportBox.Text += string.Format("{0}.\r\n Ошибка: не удалось построить тесты для системы. Подрбнее: {1} \r\n\r\n", fileName, ex.Message);
                    errorsCounter++;
                    continue;
                }

                // saving success circuit
                sucessCircuits.Add(circuitReader.Circuit);

                // saving success file name
                successCircuitsFiles.Add(fileName);

                // saving system
                sucessSystems.Add(system);

                reportBox.Text += string.Format("{0}.\r\n Успех: тесты построены ({1}). Paths: {2}, robust: {3}, relativly robust: {4}, non-robust: {5}, a-,b-tests: {6}. \r\n\r\n", fileName, circuitReader.Circuit.CountPaths(), pdfAnalyzer.RobustTest.Count + pdfAnalyzer.NonRobustRelativelyRobusTest.Count + pdfAnalyzer.NonRobustTest.Count, pdfAnalyzer.RobustTest.Count, pdfAnalyzer.NonRobustRelativelyRobusTest.Count, pdfAnalyzer.NonRobustTest.Count, abfAnalyzer.AbTest.Count);
            }


            // showing select folder dialog
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK &&
                folderBrowserDialog1.SelectedPath != String.Empty)
            {
                // output folder selected

                // printing tests to files
                for (var i = 0; i < successCircuitsFiles.Count; i++)
                {
                    var outputStr = String.Empty;

                    var robustTests = pdfTests[i].RobustTest;
                    var nonRobustTests = pdfTests[i].NonRobustTest;
                    var nonRobustRelativelyRobustTests = pdfTests[i].NonRobustRelativelyRobusTest;
                    var abfTests = abTests[i].AbTest;

                    // retrieving circuit object
                    var circuit = sucessCircuits[i];

                    if (oneFileRadioButton.Checked)
                    {
                        // all in one file

                        // printing header
                        outputStr = String.Empty;
                        outputStr += ".type fd\r\n";
                        outputStr += ".i " + circuit.Inputs.Count + "\r\n";
                        outputStr += ".o " + circuit.Outputs.Count + "\r\n";
                        outputStr += ".p " +
                                     ((robustTests.Count + nonRobustTests.Count + nonRobustRelativelyRobustTests.Count)*
                                      2 + abfTests.Count) + "\r\n";


                        // splitter
                        if (robustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                            //outputStr += "#robust PD tests";
                            //outputStr += "\r\n";
                            //outputStr += "\r\n";
                        }

                        // printing robust test
                        foreach (var test in robustTests)
                        {
                            // determing function characteristic
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = (int) test.Data;
                            funcChar[funcNum] = BooleanValue.True;

                            outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                        }

                        // splitter
                        if (robustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                            //outputStr += "#non-robust PD tests";
                            //outputStr += "\r\n";
                            //outputStr += "\r\n";
                        }

                        // printing relatively-robust test
                        foreach (var test in nonRobustRelativelyRobustTests)
                        {
                            // determing function characteristic
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = (int) test.Data;
                            funcChar[funcNum] = BooleanValue.True;

                            outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                        }

                        // splitter
                        /*if (nonRobustRelativelyRobustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }*/

                        // printing non-robust test
                        foreach (var test in nonRobustTests)
                        {
                            // determing function characteristic
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = (int) test.Data;
                            funcChar[funcNum] = BooleanValue.True;

                            outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                        }


                        // splitter
                        if (nonRobustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                            //outputStr += "#a-,b-tests";
                            //outputStr += "\r\n";
                            //outputStr += "\r\n";
                        }


                        // printing a-,b-tests
                        foreach (var test in abfTests)
                        {
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = sucessSystems[i].Functions.IndexOf(test.Function);
                            funcChar[funcNum] = BooleanValue.True;
                            outputStr += string.Format("{0} {1}\r\n", test.Vector, funcChar);
                        }


                        // splitter
                        if (nonRobustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }


                        // printing footer
                        outputStr += ".e";


                        // writing file
                        var fileName = Path.GetFileNameWithoutExtension(successCircuitsFiles[i]) + "_fulltest.test";
                        var outputFilePath = folderBrowserDialog1.SelectedPath + Path.DirectorySeparatorChar + fileName;

                        try
                        {
                            var streamWriter = new StreamWriter(outputFilePath);
                            streamWriter.Write(outputStr);
                            streamWriter.Close();
                        }
                        catch (Exception ex)
                        {
                            reportBox.Text +=
                                string.Format("{0}. Ошибка: не удалось записать в файл. Подрбнее: {1} \r\n\r\n",
                                              fileName, ex.Message);
                            continue;
                        }
                    }
                    else if (splitFilesRadioButton.Checked)
                    {
                        String fileName;
                        String outputFilePath;

                        // ----------------------------------------------------------------------------------------------
                        // Robust
                        // ----------------------------------------------------------------------------------------------

                        // printing header
                        outputStr = String.Empty;
                        outputStr += ".type fd\r\n";
                        outputStr += ".i " + circuit.Inputs.Count + "\r\n";
                        outputStr += ".o " + circuit.Outputs.Count + "\r\n";
                        outputStr += ".p " + robustTests.Count * 2 + "\r\n";


                        // splitter
                        if (robustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }

                        // printing robust test
                        foreach (var test in robustTests)
                        {
                            // determing function characteristic
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = (int)test.Data;
                            funcChar[funcNum] = BooleanValue.True;

                            outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                        }


                        // splitter
                        if (robustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }


                        // printing footer
                        outputStr += ".e";


                        // writing file
                        fileName = Path.GetFileNameWithoutExtension(successCircuitsFiles[i]) + "_robust.test";
                        outputFilePath = folderBrowserDialog1.SelectedPath + Path.DirectorySeparatorChar + fileName;

                        try
                        {
                            var streamWriter = new StreamWriter(outputFilePath);
                            streamWriter.Write(outputStr);
                            streamWriter.Close();
                        }
                        catch (Exception ex)
                        {
                            reportBox.Text +=
                                string.Format("{0}. Ошибка: не удалось записать в файл. Подрбнее: {1} \r\n\r\n",
                                              fileName, ex.Message);
                        }


                        // ----------------------------------------------------------------------------------------------
                        // Non-Robust
                        // ----------------------------------------------------------------------------------------------

                        // printing header
                        outputStr = String.Empty;
                        outputStr += ".type fd\r\n";
                        outputStr += ".i " + circuit.Inputs.Count + "\r\n";
                        outputStr += ".o " + circuit.Outputs.Count + "\r\n";
                        outputStr += ".p " + (nonRobustTests.Count + nonRobustRelativelyRobustTests.Count) * 2 + "\r\n";


                        // splitter
                        if (robustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }

                        // printing relatively-robust test
                        foreach (var test in nonRobustRelativelyRobustTests)
                        {
                            // determing function characteristic
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = (int)test.Data;
                            funcChar[funcNum] = BooleanValue.True;

                            outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                        }

                        // printing non-robust test
                        foreach (var test in nonRobustTests)
                        {
                            // determing function characteristic
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = (int)test.Data;
                            funcChar[funcNum] = BooleanValue.True;

                            outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                        }


                        // splitter
                        if ((nonRobustRelativelyRobustTests.Count + nonRobustTests.Count) > 0)
                        {
                            outputStr += "\r\n";
                        }


                        // printing footer
                        outputStr += ".e";


                        // writing file
                        fileName = Path.GetFileNameWithoutExtension(successCircuitsFiles[i]) + "_nonrobust.test";
                        outputFilePath = folderBrowserDialog1.SelectedPath + Path.DirectorySeparatorChar + fileName;

                        try
                        {
                            var streamWriter = new StreamWriter(outputFilePath);
                            streamWriter.Write(outputStr);
                            streamWriter.Close();
                        }
                        catch (Exception ex)
                        {
                            reportBox.Text +=
                                string.Format("{0}. Ошибка: не удалось записать в файл. Подрбнее: {1} \r\n\r\n",
                                              fileName, ex.Message);
                        }


                        // ----------------------------------------------------------------------------------------------
                        // AB
                        // ----------------------------------------------------------------------------------------------

                        // printing header
                        outputStr = String.Empty;
                        outputStr += ".type fd\r\n";
                        outputStr += ".i " + circuit.Inputs.Count + "\r\n";
                        outputStr += ".o " + circuit.Outputs.Count + "\r\n";
                        outputStr += ".p " + abfTests.Count + "\r\n";


                        // splitter
                        if (robustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }

                        // printing a-,b-tests
                        foreach (var test in abfTests)
                        {
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = sucessSystems[i].Functions.IndexOf(test.Function);
                            funcChar[funcNum] = BooleanValue.True;
                            outputStr += string.Format("{0} {1}\r\n", test.Vector, funcChar);
                        }


                        // splitter
                        if (abfTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }


                        // printing footer
                        outputStr += ".e";


                        // writing file
                        fileName = Path.GetFileNameWithoutExtension(successCircuitsFiles[i]) + "_ab.test";
                        outputFilePath = folderBrowserDialog1.SelectedPath + Path.DirectorySeparatorChar + fileName;

                        try
                        {
                            var streamWriter = new StreamWriter(outputFilePath);
                            streamWriter.Write(outputStr);
                            streamWriter.Close();
                        }
                        catch (Exception ex)
                        {
                            reportBox.Text +=
                                string.Format("{0}. Ошибка: не удалось записать в файл. Подрбнее: {1} \r\n\r\n",
                                              fileName, ex.Message);
                        }
                    }
                }
            }


            if (errorsCounter == 0)
            {
                MessageBox.Show("Построение тестов завершено!");
            }
            else
            {
                MessageBox.Show(string.Format("Во время построения тестов возникло {0} ошибок", errorsCounter));
            }
        }
    }
}
